Chapter 6

Checking Form Data


CONTENTS

Almost every Web site, especially those run by commercial or semi-commercial organizations, solicits information from the user. Whether it's a simple request for further information or the user places a complex order, the information that you as webmaster receive is by and large unchecked, and you therefore rely upon the user to enter the details correctly.

The usual remedy to this is to write a server-side CGI script, which is not too onerous a task. However, the user must wait for the information to travel to the server, the script to run, and a new Web page to appear in the browser before he finds out whether his information is within the limits. If the information isn't valid, he re-enters the offending section and waits again. This current method of data verification obviously wastes time and bandwidth and assumes that you have access to the server's CGI-BIN or CGI-LOCAL directories and that you have the resources to create a server-side script in languages such as Perl or PHP/FI.

When you add client-side data verification, you can perform all this verification at the browser. The user is immediately aware-even as he is typing-of whether the data is acceptable. You cannot stop the mischievous netizens who insist on filling out forms using e-mail addresses such as me@imnottelling.com, but at least you can do something to reduce the amount of totally unusable information.

This chapter concentrates on the data-verification methods you can add to a current HTML form without using ActiveX controls. Part of Chapter 16, "Real-Life Examples II," shows you how to build an interactive form with ActiveX controls and the HTML layout control.

The main object of the exercise is to stop poorly formatted data or data that doesn't fit your criteria from reaching the server. This means that you have to perform some type of validation on the data before it is submitted. The form object has an OnSubmit event that is fired either when the user clicks the Submit button or when the script calls the form object's submit method-ideal for handling the validation process.

Alerting Users During the Data Entry

Prior to submission, while the user is entering data, you can use several methods to alert the user to a problem with his input. The HTML text box has an OnChange event that fires when the focus moves away from the text box only if the text is different from the last time the event fired. For example, you can enter, This is some text, into an empty HTML text box, and the OnChange event fires when you move to the next text box or control. Return to the text box, delete the word text, retype it, and move away. Because the text is unchanged, the OnChange event doesn't fire-quite logical really!

Note
The ActiveX text box Change() event does not work in this way. The Change() event is fired with every keystroke, and placing validation code in the Change() event handler can drive a user to distraction if it is not implemented thoughtfully.

Using the OnChange event, you can test for data acceptability and caution the user if the test fails. Of course, this method on its own doesn't really solve your problem because the user can simply choose to click OK on the Alert box and then ignore its warning-which means you still receive bad data at the server. There is no substitute for preventing poor data from being submitted. However, ongoing verification during the entry phase used in conjunction with a final verification helps both you and the users.

A Data Verification Example

Listing 6.1 shows the source code for the example you use in this chapter; Figure 6.1 shows the Web page when it's run in the browser. It contains five HTML text boxes. The first is an optional field that contains no verification. Two fields require a numerical entry, one requires a date, and one asks for the user's e-mail address. As the user enters data and moves to the next field, the data is verified, and if the script finds a problem, it alerts the user. The verification takes place in a series of functions that can be called from any of the fields, which allows for speedy maintenance should you need to add further verifiable fields to the form. Finally, the user clicks the submit button, which is a normal button. The data is reverified, and if it's found to be correct, the form data is submitted to the server.

Figure 6.1 : The sample form in the browser.


Listing 6.1. The sample source code for validate.htm.
<HTML>
<HEAD>
<TITLE>Data Validation</TITLE>

1:<SCRIPT LANGUAGE="vbscript">

2:Function ValidateNumber(ByVal TheNumber, ByVal FieldName)
3: If Not IsNumeric(TheNumber) Then
4:  x = MsgBox("Invalid Numeric Entry",16,FieldName)
5:  ValidateNumber = False
6: Else
7:  ValidateNumber = True
8: End If
9:End Function

10:Function ValidateDate(ByVal TheDate, ByVal FieldName)
11: If Not IsDate(TheDate) Then
12:  x = MsgBox("Invalid Date",16,FieldName)
13:  ValidateDate = False
14: Else
15:  ValidateDate = True
16: End If
17:End Function

18:Function IsEMail(ByVal TheEMail, ByVal FieldName)

19: If InStr(TheEMail, "@") > 2 Then
20:    If Len(TheEMail) - InStr(TheEMail, "@") > 6 Then
21:       If InStr(InStr(TheEMail, "@"),TheEMail,".") > 0 Then
22:          If Len(TheEMail) - InStr(InStr(TheEMail, "@"),TheEMail,".") => 2 		Then
23:             ValidateEMail = True
24:          Else
25:             ValidateEMail = False
26:          End If
27:       Else
28:          ValidateEMail = False
29:       End If
30:    Else
31:       ValidateEMail = False
32:    End If
33: Else
34:    ValidateEMail = False
35: End If

36: If ValidateEMail = True Then
37:    IsEMail = True
38: Else
39:    x = MsgBox("Invalid Entry",16,FieldName)
40:    IsEMail = False
41:End If

42:End Function


43:Sub txtQty_OnChange
44: x = ValidateNumber(Document.Form1.txtQty.Value, "Quantity")
45:End Sub

46:Sub txtSize_OnChange
47: x = ValidateNumber(Document.Form1.txtSize.Value, "Size")
48:End Sub

49:Sub txtDate_OnChange
50: x = ValidateDate(Document.Form1.txtDate.Value, "Date")
51:End Sub

52:Sub txtEmail_OnChange
53: x = IsEMail(Document.Form1.txtEmail.Value, "EMail")
54:End Sub

55:Sub cmdButton1_OnClick
56:  If ValidateNumber(Document.Form1.txtQty.Value, "Quantity") And _
57:    ValidateDate(Document.Form1.txtDate.Value, "Date") And _
58:    ValidateNumber(Document.Form1.txtSize.Value, "Size") And _
59:    IsEMail(Document.Form1.txtEmail.Value, "EMail") Then
60:      Document.Form1.Submit
61:  Else
62:      Exit Sub
63:  End If
64:End Sub

65:</SCRIPT>

</HEAD>

<BODY BGCOLOR="white">
<FORM NAME="Form1" ACTION="http://www.vbscripts.com/test/formtest.phtml" 
METHOD=POST>
<PRE>
Your Name       <INPUT TYPE="text" NAME="txtUserName">
Quantity        <INPUT TYPE="text" NAME="txtQty">
Size in Metres  <INPUT TYPE="text" NAME="txtSize">
Date            <INPUT TYPE="text" NAME="txtDate">
Your EMail      <INPUT TYPE="text" NAME="txtEmail">
<INPUT TYPE="Button" NAME="cmdButton1" VALUE="Submit Now">
</PRE>
</FORM>
</BODY>
</HTML>

Creating the Form

The form itself is a straightforward HTML form; no surprises here. The form's action is set to a PHP/FI-scripted HTML page, which simply displays the data entered in the form. The HTML for the form is shown in the following code block:

<FORM NAME="Form1" ACTION="http://www.vbscripts.com/test/formtest.phtml" 
METHOD=POST>
<PRE>
Your Name       <INPUT TYPE="text" NAME="txtUserName">
Quantity        <INPUT TYPE="text" NAME="txtQty">
Size in Metres  <INPUT TYPE="text" NAME="txtSize">
Date            <INPUT TYPE="text" NAME="txtDate">
Your EMail      <INPUT TYPE="text" NAME="txtEmail">
<INPUT TYPE="Button" NAME="cmdButton1" VALUE="Submit Now">
</PRE>
</FORM>

Validating Numeric Data Entries

Each of the verifications is held in a separate function. Functions in VBScript are procedures that return a value to the code that called them. The following code is the function that validates the numerical data:

2:Function ValidateNumber(ByVal TheNumber, ByVal FieldName)
3: If Not IsNumeric(TheNumber) Then
4:  x = MsgBox("Invalid Numeric Entry",16,FieldName)
5:  ValidateNumber = False
6: Else
7:  ValidateNumber = True
8: End If
9:End Function

The function prototype in line 2 requires that two values are passed into the function: first, TheNumber, which is the value to be validated, and second, FieldName, which is the name of the field being validated.

The keyword ByVal instructs the scripting engine to pass only the value of these variables into the function. For more detail on functions and procedures, see Chapter 9 "Making Your Program Flow."

Line 3, where the actual verification takes place, introduces you to a new concept, negation.

Suppose x equals 10. The statement If x = 10 Then returns True, and the lines following the If... statement execute. However, reversing the condition is known as negation; if x is not equal to 10, the code lines between the If and End If execute if you write the statement as If Not x = 10 Then. To learn more about If...Then conditional statements, see Chapter 9.

Determining whether a series of characters is numeric isn't an easy task if you consider the logic that must be performed. However, VBScript's built-in checking functions include IsNumeric. If the entered string can be converted to a number, the function returns True; if it cannot be converted, the function returns False. Remember that all data coming from an HTML form is string data; for instance, the number 400 appears to the program as "400".

Lines 4 and 5 execute only if the data entered into the field cannot be converted into a number (such as non-numeric characters). Line 4 displays a message box to the user informing him or her that the entry is invalid; the message box uses an OK button and a Stop icon. The user then has the option to return to the field and retype the entry. Line 5 sets the function's own return value to False.

Line 6 is part of the If...Then...Else conditional statement. Line 7, which executes only if the IsNumeric function returns True, sets the function's own return value to True.

Lines 8 and 9 finish the If...Then statement and end the function, passing execution back to the code that called the function and returning a value of either True or False.

Validating Date Entries

The function for validating the date in this example is very similar to the numerical validation function:

10:Function ValidateDate(ByVal TheDate, ByVal FieldName)
11: If Not IsDate(TheDate) Then
12:  x = MsgBox("Invalid Date",16,FieldName)
13:  ValidateDate = False
14: Else
15:  ValidateDate = True
16: End If
17:End Function

The function prototype in line 10 requires that two values are passed into the function: first, TheDate, which is the date entered by the user to be validated, and second, FieldName.

Line 11 is where the date verification takes place. To learn more about If...Then conditional statements, see Chapter 9.

The IsDate function, which is built into the VBScript engine, saves you from writing a huge script to cover all possible combinations that are valid dates-12-Jun-96, 12-June-1996, 12-6-96, 12/06/96, 06/12/96, and so on. The IsDate function operates on the user's date setting in the International section of his Windows system. What is a valid date in one country might be invalid in another. Suppose a user in Sweden types the date 96.06.12, which is a valid date format in Sweden, because his Windows system is set to Swedish date formats. IsDate correctly returns True. However, this presents a problem when you send the data to the server.

Instead of writing a mammoth server-side script to handle every possible date format in the world, you can restrict the date to a certain format and display it to the user-for example, mm-dd-yy. You can then create a script that checks for this rather rigid date format.

Chapter 8 "Adding Date and Time Functions," shows a more flexible alternative that breaks the user's date input into month, day, and year and rearranges it to your desired format.

Lines 12 and 13 execute only if the data entered into the field is not a valid date. Line 14 is part of the If...Then...Else conditional statement. Line 15, which executes only if the IsDate function returns True, sets the function's own return value to True.

Lines 16 and 17 finish the If...Then statement and end the function, passing execution back to the code that called the function and returning a value of either True or False.

Verifying String Data Entries

Verifying string data can become somewhat complicated because you must decide what the string pattern should look like and hard code that pattern into the script, as the following code shows:

18:Function IsEMail(ByVal TheEMail, ByVal FieldName)

19: If InStr(TheEMail, "@") > 2 Then
20:    If Len(TheEMail) - InStr(TheEMail, "@") > 6 Then
21:       If InStr(InStr(TheEMail, "@"),TheEMail,".") > 0 Then
22:          If Len(TheEMail) - InStr(InStr(TheEMail, "@"),TheEMail,".") => 2 
		Then
23:             ValidateEMail = True
24:          Else
25:             ValidateEMail = False
26:          End If
27:       Else
28:          ValidateEMail = False
29:       End If
30:    Else
31:       ValidateEMail = False
32:    End If
33: Else
34:    ValidateEMail = False
35: End If

36: If ValidateEMail = True Then
37:    IsEMail = True
38: Else
39:    x = MsgBox("Invalid Entry",16,FieldName)
40:    IsEMail = False
41:End If

42:End Function

The pattern of an e-mail address at minimum should be ***@***.***, where * is alphanumeric. Lines 19 to 22 check for this minimum pattern.

Line 19 uses the InStr function to find the @ character somewhere in the string. InStr returns the position of the character if found or 0 if it is not found within the search string. The criteria you set for the first part of the pattern is that the @ character must appear at least three characters in from the left. As a result, the InStr function in line 19 must return at least 3 for the first part of the pattern to be true.

If the first part succeeds, the second part of the pattern dictates that there must be a minimum of seven characters after the @ symbol. Line 20 tests this condition by subtracting the position of the @ symbol from the length of the overall string, which is found with the Len function.

20:    If Len(TheEMail) - InStr(TheEMail, "@") > 6 Then

In the minimum pattern, the length of the string is 11 characters, and the @ symbol resides at position 4; therefore, the minimum number of characters to the right of the @ is 7. Line 20 tests for any amount greater than 6.

The next stage is a little more complex. Line 21 determines whether a . (period) appears somewhere after the @ symbol. Notice that the InStr function appears twice in line 21:

21:       If InStr(InStr(TheEMail, "@"),TheEMail,".") > 0 Then

The full syntax of InStr is

InStr(Start,String1,String2) 

In Line 21, you use the position of the @ symbol to determine where InStr should start its search for the . symbol. If it does find a . symbol somewhere after the @ symbol, the function returns the position of the character, and you can proceed to the final part of the pattern, which is determining whether the . symbol appears at least two characters in from the right. As you know, the e-mail address could be a .com, .edu, .com.bh, .co.uk, and so on.

22:          If Len(TheEMail) - InStr(InStr(TheEMail, "@"),TheEMail,".") => 2 
		Then

Line 22 uses the position of the @, the position of the ., and the overall length of the string to determine how many characters appear after the . symbol. Two or more characters at the end makes the pattern complete and fits our definition of the minimum e-mail address. Of course, as I said earlier, this doesn't stop someone from entering aaa@aaa.aaa.

If the validation of the e-mail address fails at any stage, the variable ValidateEmail is set to False. Finally, the script makes a check of the variable, and if all is well, the function's own return value is set to True. If the data is invalid, the return value is set to False, and a warning message is displayed to the user.

Implementing an OnChange Event

Where were all these functions called? What set them going? When the user enters a new or changed value in one of the text boxes and then moves away from that text box, an OnChange event fires. The following segment shows the event handlers for each of the text boxes, not including the first text box, which is not validated:

43:Sub txtQty_OnChange
44: x = ValidateNumber(Document.Form1.txtQty.Value, "Quantity")
45:End Sub

46:Sub txtSize_OnChange
47: x = ValidateNumber(Document.Form1.txtSize.Value, "Size")
48:End Sub

49:Sub txtDate_OnChange
50: x = ValidateDate(Document.Form1.txtDate.Value, "Date")
51:End Sub

52:Sub txtEmail_OnChange
53: x = IsEMail(Document.Form1.txtEmail.Value, "EMail")
54:End Sub

I put these event handlers out on their own so that you can read them easily, but it is legal to write the event handler within the HTML definition of the text box in
this way:

 <INPUT LANGUAGE="vbscript" TYPE=text ONchANGE=" x = call 
ValidateNumber(Document.Form1.txtSize.value,&quot;Size&quot;)"
         NAME="txtSize">

In fact, if you create these event handlers within the ActiveX Control Pad, that is exactly the automatic code that the Control Pad creates.

Implementing a Validate and Submit Routine

As mentioned in the introduction to the chapter, the main goal of data validation is to reduce the amount of poor data or to eliminate it altogether. What the example accomplishes so far is really a cosmetic exercise in informing the user of the invalidity of his data entry, hoping that this spurs him into action to change the entry. However, the script doesn't guarantee this. The ultimate precaution is to hide the data submission behind a wall of validation. Only after all the validation checks that you specify are completed successfully is the data submitted to the server, as you can see from the following code:

55:Sub cmdButton1_OnClick
56:  If ValidateNumber(Document.Form1.txtQty.Value, "Quantity") And _
57:    ValidateDate(Document.Form1.txtDate.Value, "Date") And _
58:    ValidateNumber(Document.Form1.txtSize.Value, "Size") And _
59:    IsEMail(Document.Form1.txtEmail.Value, "EMail") Then
60:      Document.Form1.Submit
61:  Else
62:      Exit Sub
63:  End If
64:End Sub

Lines 56 through 59 are actually the same line, joined together at runtime with the special underscore character. All checks must return True for the overall statement to be True. One of the nice things about this method of checking is that each check is carried out regardless of the result of the last. The user receives a prompt for all fields that fail the test.

Note
Because you use functions to perform the validation, you can call them from many different places within your script, rather than rewrite the same code over and over.

When the data is in order, line 60 calls the form's submit method and the data is on its way.

Using the OnSubmit Event

The ActiveX and VBScript documentation refers to using the OnSubmit event to perform data validation in such a way that prevents form submission if the validation fails. However, the documentation does not describe the very odd way in which the OnSubmit event must be implemented.

OnSubmit is an event and, as such, the code attached to that event should be within an event handler. But the OnSubmit event must be used as though it is a function. Here's how you declare the prototype for the OnSubmit "event."

Function myForm_OnSubmit()

This is done so that OnSubmit can return a value. OnSubmit returns True if the form data is validated, in which case the form data is submitted; it returns False if the form data fails validation, in which case the form data is not submitted.

Within the OnSubmit event handler/function, you can include calls to all your validation routines, as this amendment to the previous example shows:

55:Function Form1_OnSubmit
56:  If ValidateNumber(Document.Form1.txtQty.Value, "Quantity") And _
57:    ValidateDate(Document.Form1.txtDate.Value, "Date") And _
58:    ValidateNumber(Document.Form1.txtSize.Value, "Size") And _
59:    IsEMail(Document.Form1.txtEmail.Value, "EMail") Then
60:      Form1_OnSubmit = True
61:  Else
62:      Form1_OnSubmit = False
63:  End If
64:End Sub

To use this code with the previous example, you would also have to change the button control type to Submit.

Workshop Wrap-Up

In this chapter, you saw that client-side data verification is economical in terms of time and bandwidth. You can use several methods to ensure that data is formatted correctly and to alert users to any problems with their data along the way. Here's a brief summary:

Next Steps

You have just learned how to interactively and programatically validate data and then submit that data to the server. To brush up on your skills to create even more complex validation routines, look at the following chapters:

Q&A

Q:
If I put my validation routines on the client side, isn't it possible for someone to see what could be sensitive information?
A:
Yes, and for this reason, you should be careful what you place in a client-side validation routine. For example, don't write a script that says something like if myform.password.value <> "letmein" then.... If you do, you've just blown it!